using System;
using System.IO;
using System.Diagnostics;
using System.Globalization;

namespace Waymex.Diagnostics
{
	/// <summary>
	/// This class allows trace information to be written to a Trace Log file. 
	/// The object is static and can be used without an instance of the class being created. 
	/// If a valid TraceFilename has been set then objects will write to the 
	/// class to log information to the Trace Log. The type of information logged will 
	/// depend on the setting of the TraceType property.
	/// During development, any Debug.Write type statements will be automatically added 
	/// to the trace log. 
	/// </summary>
	public sealed class TraceLog
	{
		private const string LOG_LINE = "------------------------------------------------------------------";

		static StreamWriter m_errorFile;
		static TextWriterTraceListener m_fileListener;
		static TraceSwitch m_tsTraceswitch;
		static string m_sFilename;
		/// <summary>
		/// Constructor, creates the Trace Switch and the TraceSwitch Level.
		/// </summary>
        private TraceLog()
        {
        }
        private static void InitialiseTraceSwitch()
        {
            m_tsTraceswitch = new TraceSwitch("TraceSwitch", "Trace Switch for Library Objects"); //set these with constructor?
            m_tsTraceswitch.Level = TraceLevel.Verbose; //set this with constructor or property or both
        }
		/// <summary>
		/// Write a message to the Trace Log.
		/// </summary>
		public static void WriteMessage(string message)
		{
			WriteMessage(message,TraceLevel.Verbose ,false ,false ,false);
		}
		/// <summary>
		/// Write a message to the Trace Log.
		/// </summary>
		public static void WriteMessage(string message, TraceLevel messageType)
		{
			WriteMessage(message, messageType, false, false, false);
		}
		/// <summary>
		/// Write a message to the Trace Log.
		/// </summary>
		public static void WriteMessage(string message, TraceLevel messageType, bool time)
		{
			WriteMessage(message, messageType, time, false, false);
		}
		/// <summary>
		/// Write a message to the Trace Log.
		/// </summary>
		public static void WriteMessage(string message, TraceLevel messageType, bool time, bool precedingLine)
		{
			WriteMessage(message, messageType, time, precedingLine, false);
		}
		/// <summary>
		/// Write a message to the Trace Log.
		/// </summary>
		public static void WriteMessage(string message, TraceLevel messageType, bool time, bool precedingLine, bool followingLine)
		{
					
			string sTime ="";

			if(m_sFilename == null)
				return;
			if(m_sFilename.Length == 0)
				return;

            if (m_tsTraceswitch == null)
                InitialiseTraceSwitch();

			//if the current tracswitch level is >= to the passed in value then log
			if(m_tsTraceswitch.Level.CompareTo(messageType) >= 0)
			{
				if(time)
					sTime = string.Concat(DateTime.Now.ToString("dd-mmm-yyyy hh:mm:ss.ss"), " - ");
				
				if(precedingLine)
					Trace.WriteLine(LOG_LINE);

				Trace.WriteLine(String.Concat(sTime, message));

				if(followingLine)
					Trace.WriteLine(LOG_LINE);

				Trace.Flush();
			}		
		}
		/// <summary>
		/// Sets the Trace file name, setting this to a valid 
		/// file causes trace output from the GPS Library to be written to the file.
		/// </summary>
		public static string TraceFileName
		{
		
			get
			{
				return m_sFilename;
			}
		
			set
			{
                if (m_tsTraceswitch == null)
                    InitialiseTraceSwitch();

				m_sFilename = value;
				m_errorFile = File.AppendText(m_sFilename);
				m_fileListener = new TextWriterTraceListener(m_errorFile);
				Trace.Listeners.Add(m_fileListener);
			}
		}
		/// <summary>
		/// Sets the Trace level and will be one of the following. Error, Info, Off, Verbose or Warning.
		/// </summary>
		public static TraceLevel TraceType
		{
			get
			{
				return m_tsTraceswitch.Level;
			}
			set
			{
                if (m_tsTraceswitch == null)
                    InitialiseTraceSwitch();
                m_tsTraceswitch.Level = value;
			}
		}
		/// <summary>
		/// Writes a header to the Trace File which contains diagnostic information. Typically this would
		/// be called only once at the begining of the program execution.
		/// </summary>
		public static void WriteHeader()
		{

			if(m_sFilename == null)
				return;

			if(m_sFilename.Length == 0)
				return;

            if (m_tsTraceswitch == null)
                InitialiseTraceSwitch();

			Trace.WriteLine(LOG_LINE);
			Trace.WriteLine(String.Concat(DateTime.Now.ToString("dd-mmm-yyyy hh:mm:ss.ss")));
			Trace.WriteLine(String.Concat("Application Version: ", Environment.Version.ToString()));
			Trace.WriteLine(String.Concat("Current Path: ", Environment.CommandLine));
			Trace.WriteLine(String.Concat("Machine Name: ", Environment.MachineName));
			Trace.WriteLine(String.Concat("Operating System: ", Environment.OSVersion.ToString()));
			Trace.WriteLine(String.Concat("Working Set: ", Environment.WorkingSet.ToString(CultureInfo.InvariantCulture)));
			Trace.WriteLine(String.Concat("Domain: ", Environment.UserDomainName.ToString(CultureInfo.InvariantCulture)));
			Trace.WriteLine(String.Concat("User: ", Environment.UserName.ToString(CultureInfo.InvariantCulture)));
			Trace.WriteLine(LOG_LINE);

            Trace.Flush();

		}
		/// <summary>
		/// Writes Exception information, including stack trace information to the Trace File.
		/// </summary>
		public static void WriteError(System.Exception exception)
		{
			if(m_sFilename == null)
				return;

			if(m_sFilename.Length == 0)
				return;

            if (m_tsTraceswitch == null)
                InitialiseTraceSwitch();

			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, "Exception: ");
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, String.Concat("Error: ", exception.Message));
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, exception.ToString());
			
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, "Base Exception: ");
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, String.Concat("Error: ", exception.GetBaseException().Message));
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, LOG_LINE);
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, exception.GetBaseException().ToString());
			
			Trace.WriteLineIf(m_tsTraceswitch.TraceError, exception.GetBaseException().TargetSite);
			Trace.WriteLineIf(m_tsTraceswitch.TraceVerbose, "StackTrace: ");
			Trace.WriteLineIf(m_tsTraceswitch.TraceVerbose, exception.StackTrace);
			Trace.WriteLineIf(m_tsTraceswitch.TraceVerbose, "StackTrace: ");
			Trace.WriteLineIf(m_tsTraceswitch.TraceVerbose, LOG_LINE);

			
			Trace.Flush();
		}
		/// <summary>
		/// Closes all resources and disposes of the object. 
		/// </summary>
		public static void Dispose()
        {
            if (m_tsTraceswitch != null)
            {
                if (m_tsTraceswitch.Level == System.Diagnostics.TraceLevel.Off)
                    return;
            }
			m_errorFile.Flush();
			m_errorFile.Close();
		}
	}
}

